package com.funmi.lizip.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.TimeZone;

/**
 * @ClassName: WebMvcConfig
 * @Description: 用JavaBean的形式代替xml进行框架的个性化设置
 * @Author: Ytra1rom
 * @Date: 2022/7/27 20:35
 * @Version: 1.0
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 从配置文件中获取日期格式化参数，如果没有就使用默认格式化字符串 ‘: yyyy-MM-dd HH:mm:ss’
     */
    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT = "yyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    private static final String TIME_ZONE = "GMT+8";

    /**
     * 处理日期格式
     * @param registry 日期格式化注册类
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        //创建一个SpringMVC准备好的日期格式化类
        //这个类只适用于Date类型
        DateFormatter dateFormatter = new DateFormatter();
        dateFormatter.setFallbackPatterns(DEFAULT_DATE_FORMAT, "yyyy/MM/dd HH:mm:ss",
                DEFAULT_DATETIME_PATTERN, "yyyy/MM/dd HH:mm:ss",
                "yyyy-MM-dd 'T' HH:mm");
        registry.addFormatter(dateFormatter);

        //配置JDK8的新日期API处理格式
        final DateTimeFormatterRegistrar formatterRegistrar = new DateTimeFormatterRegistrar();

        //处理LocalTime
        formatterRegistrar.setTimeFormatter(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
        //处理LocalDate
        formatterRegistrar.setDateFormatter(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
        //处理LocalDateTime
        formatterRegistrar.setDateTimeFormatter(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN));
        formatterRegistrar.registerFormatters(registry);
    }

    /**
     * 处理新时间类型和为null时的序列化
     * @param converters 消息转换类
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //这里不能直接创建新的MappingJackson2HttpMessageConverter对象添加，会影响swagger-ui使用
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper objectMapper = new ObjectMapper();

                //指定时区
                objectMapper.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));

                //日期类型字符串处理
                objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATETIME_PATTERN));

                //设置参数为null时不序列化
                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

                //Java8新日期处理
                JavaTimeModule javaTimeModule = new JavaTimeModule();
                javaTimeModule.addSerializer(LocalDateTime.class, new
                        LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
                javaTimeModule.addSerializer(LocalDate.class, new
                        LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
                javaTimeModule.addSerializer(LocalTime.class, new
                        LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
                javaTimeModule.addDeserializer(LocalDateTime.class, new
                        LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
                javaTimeModule.addDeserializer(LocalDate.class, new
                        LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
                javaTimeModule.addDeserializer(LocalTime.class, new
                        LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

                // 解决JavaScript 无法表示Long类型的问题，因为Long超出了JavaScript中number类型的范围
                javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
                objectMapper.registerModule(javaTimeModule);
                ((MappingJackson2HttpMessageConverter) converter).setObjectMapper(objectMapper);
            }
        }
    }

    /**
     * 添加跨域映射
     * @param registry 跨域注册类
     */
    /*@Override
    public void addCorsMappings(CorsRegistry registry) {
        //添加映射路径，"/**"表示允许所有路径访问
        registry.addMapping("/**")
                //可以配置多个允许跨域的前端地址
                //.allowedOrigins("http://localhost:5500")
                //.allowedOrigins("http://localhost:8081/dev")
                .allowedOrigins("*")
                //设置*表示头部没有限制
                .allowedHeaders("*")
                //开放哪些Http方法，允许跨域访问
                .allowedMethods("POST", "GET", "PUT", "DELETE", "OPTIONS")
                //一小时预检一次
                .maxAge(3600);
        // 是否允许发送Cookie信息
        //.allowCredentials(true);
    }*/
    /**
     * 静态资源映射
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 当访问/file下的资源时，会到/root/myFile/下去找
        // 例如访问：http://localhost:8080/file/1.png时会去找/root/myFile/1.png
        registry.addResourceHandler("/uploadFile/**").addResourceLocations("file:D:\\image\\");
    }

}
